/* *********************************************************************************  
 *   This file is part of GeometryPlayground.
 *
 *   GeometryPlayground is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU Affero General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   GeometryPlayground is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU Affero General Public License for more details.
 *
 *   You should have received a copy of the GNU Affero General Public License
 *   along with GeometryPlayground.  If not, see <http://www.gnu.org/licenses/>.
 **********************************************************************************/
 
import java.awt.Graphics;
import java.util.LinkedList;

abstract class ManhattanConstruct extends GeoConstruct {
	protected double[] v1={0,0,0},v2={0,0,0};//temp vectors

	protected ManhattanConstruct(){}
	public ManhattanConstruct(int t, double[] vector)
	{ type=t; setXYZ(vector); }
	public ManhattanConstruct(int t, double[] v1, double[] v2)
	{ type=t; setXYZ(v1, v2); }  
	public ManhattanConstruct(int t, ManhattanConstruct a, ManhattanConstruct b){
		double[] vec1={0,0,0}, vec2={0,0,0};
		type=t;
		constList.addLast(a);
		constList.addLast(b);
		constList.get(0).getXYZ(vec1);
		constList.get(1).getXYZ(vec2);
		this.setXYZ(vec1, vec2);
	}
	public ManhattanConstruct(int t, double[] v, ManhattanConstruct a) {
		type=t;
		constList.addLast(a);
		this.setXYZ(v);
	}
	public ManhattanConstruct(int t, LinkedList<GeoConstruct> clickedList) {
		type=t;
		for(int i=0;i<clickedList.size();i++)
			constList.addLast(clickedList.get(i));
		if (constList.size()==2) {
			double[] vec1={0,0,0}, vec2={0,0,0};
			constList.get(0).getXYZ(vec1);
			constList.get(1).getXYZ(vec2);
			this.setXYZ(vec1, vec2);
		}
		else {
		}
	}
	public ManhattanConstruct(int t, LinkedList<GeoConstruct> clickedList,double[] v){
		type=t;
		for(int i=0;i<clickedList.size();i++)
			constList.addLast(clickedList.get(i));
		if (t==GeoConstruct.DISTANCE) {
			double[] v0={0,0,0};
			constList.get(0).get(0).getXYZ(v);
			constList.get(0).get(1).getXYZ(v0);
			for (int i=0;i<2;i++) v[i]=(v[i]+v0[i])/2;
		}
		if (t==GeoConstruct.RATIO) {
			double[] v0={0,0,0};
			constList.get(0).getXYZ(v);
			constList.get(1).getXYZ(v0);
			for (int i=0;i<2;i++) v[i]=(v[i]+v0[i])/2;
		}
		setXYZ(v);
		update();
	}

	public abstract ManhattanPoint intersect(int m, ManhattanConstruct a);

	public void setXYZ(double[] vector) {
		x=vector[0]; y=vector[1]; z=0; 
		newX=x;      newY=y;      newZ=z;
	}

	public void setXYZ(double[] v1, double[] v2) {
		if (MathEqns.norm(v1,v2)>.0001) {
			if(type==LINE || type==SEGMENT){
				x=v2[0]-v1[0];y=v2[1]-v1[1];z=0;
			}
			else{
				x=-v1[1];y=v1[0];z=0;
			}
			setValid(true);
		}
		else setValid(false);
	}

	public void setNewXYZ(double[] vector) {
		if ((type<0 && MathEqns.norm(vector)>.0000001) || type>=0) {
		newX=vector[0]; newY=vector[1]; newZ=vector[2];}
		else setValidNew(false);
	}

	public void setNewXYZ(double[] v1, double[] v2) {
		if (MathEqns.norm(v1,v2)>.00001) {
			if(type==LINE || type==SEGMENT){
				newX=v2[0]-v1[0];newY=v2[1]-v1[1];newZ=0;
			}
			else{
				newX=-v1[1];newY=v1[0];newZ=0;
			}
			setValidNew(true);
		}
		else setValidNew(false);
	}

	public void translate(double[] dragStart, double[] dragNow){
		double[] vector1={0,0,0};
		getXYZ(vector1);
		for(int i=0;i<3;i++) vector1[i]+=dragNow[i]-dragStart[i];
		this.setNewXYZ(vector1);
	}
	public void transform(GeoConstruct fixedObject,double[] dragStart,double[] dragNow) {
		MathEqns.transform(fixedObject,this,dragStart,dragNow);
	}
	public static double getScale() {return 1;}
	public static void setScale(double x) {}
} // end class 


class ManhattanPoint extends ManhattanConstruct{
	protected int sz;
	public ManhattanPoint(int t, double[] vector) {super(t,vector);}
	public ManhattanPoint(int t, double[] v1, double[] v2) {super(t,v1,v2);} 
	public ManhattanPoint(int t, double[] v, ManhattanConstruct a) {super(t,v,a);}
	public ManhattanPoint(int t, ManhattanConstruct a, ManhattanConstruct b){super(t,a,b);}
	public ManhattanPoint(int t, LinkedList<GeoConstruct> clickedList,double[] v){super(t,clickedList,v);}

	public ManhattanPoint intersect(int m, ManhattanConstruct a){
		ManhattanPoint newPoint=new ManhattanPoint(LINEintLINE0,a,this);
		return newPoint;
	}

	public void draw(Graphics g, int SZ, boolean New) {
		sz=(int)MathEqns.max(4,SZ/40);
		if ((New && getValidNew()) || (!New && getValid())) { 
			if(New) getNewXYZ(v1);
			else getXYZ(v1);
			if (getType()<30) {
				g.fillOval(SZ+(int)(SZ*v1[0])-sz/2,SZ+(int)(SZ*v1[1])-sz/2,sz,sz);
				if (getLabelShown())
					g.drawString(""+(char)('A'+ID%26)+""+(ID/26),SZ+(int)(SZ*v1[0])-sz/2,SZ+(int)(SZ*v1[1])-sz/2); 
			}
		}
	}

	public boolean mouseIsOver(double[] v1, int SZ){
		double sz=MathEqns.max(6,SZ/20);
		return ((x-v1[0])*(x-v1[0])+(y-v1[1])*(y-v1[1])<sz*sz/(SZ*SZ));
	}
	
	
	protected void updatePTonLINE(){
		setValidNew(get(0).getValidNew());
		if (getValidNew()) {
			if (constList.get(0).getType()!=SEGMENT) {
				double[] newPt={0,0,0},lineSlope={0,0,0};
				double comp=0;
			constList.get(0).getNewXYZ(lineSlope);
			constList.get(0).get(1).getNewXYZ(v2);//This should be the "for sure" point
			v1[0]=v1[0]-v2[0];
			v1[1]=v1[1]-v2[1];
			MathEqns.normalize(lineSlope);
			comp=MathEqns.dotProduct(lineSlope, v1);
			newPt[0]=v2[0]+comp*lineSlope[0];
			newPt[1]=v2[1]+comp*lineSlope[1];
			newPt[2]=0;
			setNewXYZ(newPt);
			}
			else {
				double dist=1000;
				int min=0;
				double[] bn={0,0,0},nm={0,0,0};
				constList.get(0).get(0).getNewXYZ(v2);
				constList.get(0).get(1).getNewXYZ(bn);
				for (int i=0;i<127;i++) {
					nm[0]=v2[0]*i/126+bn[0]*(126-i)/126;
					nm[1]=v2[1]*i/126+bn[1]*(126-i)/126;
					if (MathEqns.norm(v1,nm)<dist) {
						dist=MathEqns.norm(v1,nm);
						min=i;
					}
				}
				nm[0]=v2[0]*min/126+bn[0]*(126-min)/126;
				nm[1]=v2[1]*min/126+bn[1]*(126-min)/126;
				nm[2]=0;
				setNewXYZ(nm);
			}
		}
	}

	protected void updatePTonCIRC(){
		setValidNew(get(0).getValidNew());
		if (getValidNew()) {
			double[] center={0,0,0}, radial={0,0,0}, u1={0,0,0},u2={0,0,0};
			constList.get(0).get(0).getNewXYZ(center);
			constList.get(0).get(1).getNewXYZ(radial);
			double r=Math.abs(center[0]-radial[0])+Math.abs(center[1]-radial[1]);
			if (center[0]<=v1[0] && center[1]<=v1[1]) {
				u1[0]=center[0]+r;	u1[1]=center[1];
				u2[0]=center[0];	u2[1]=center[1]+r;
			}
			else if (center[0]<=v1[0] && center[1]>v1[1]) {
				u1[0]=center[0]+r;	u1[1]=center[1];
				u2[0]=center[0];	u2[1]=center[1]-r;
			}
			else if (center[0]>v1[0] && center[1]<=v1[1]) {
				u1[0]=center[0]-r;	u1[1]=center[1];
				u2[0]=center[0];	u2[1]=center[1]+r;
			}
			else {
				u1[0]=center[0]-r;	u1[1]=center[1];
				u2[0]=center[0];	u2[1]=center[1]-r;
			}
			ManhattanPoint a,b,d;
			ManhattanSEGMENT c;
			a=new ManhattanPoint(POINT,u1);
			b=new ManhattanPoint(POINT,u2);
			LinkedList<GeoConstruct> temp = new LinkedList<GeoConstruct>();
			temp.add(a);	temp.add(b);
			c=new ManhattanSEGMENT(SEGMENT,temp);
			c.update();		temp.clear();	temp.add(c);
			d=new ManhattanPTonLINE(PTonLINE,temp,v1);
			d.updatePTonLINE();
			d.getNewXYZ(v2);	setNewXYZ(v2);
		}	
	}

	public void update() {
		getNewXYZ(v1);
	}
}

class ManhattanLine extends ManhattanConstruct{
	protected double[] a={0,0,0},u={0,0,0},v={0,0,0};
	public ManhattanLine(int t, LinkedList<GeoConstruct> clickedList){
		super(t,clickedList);
			x=clickedList.get(0).x-clickedList.get(1).x;
			y=clickedList.get(0).y-clickedList.get(1).y;
			z=0;
			newX=x;	newY=y;	newZ=0;
	}
	public ManhattanPoint intersect(int m, ManhattanConstruct a){
		ManhattanPoint newPoint;
		if(a.getType()==0)
			newPoint=intersect(m,(ManhattanCircle)a);
		else
			newPoint=intersect(m,(ManhattanLine)a);
		return newPoint;
	}
	public ManhattanPoint intersect(int m, ManhattanLine a){
		double[] v={0,0,0};
		ManhattanPoint newPoint=new ManhattanLINEintLINE(LINEintLINE0,a,this);
		newPoint.update();
		newPoint.getNewXYZ(v);
		newPoint.setXYZ(v);
		return newPoint;
	}
	public ManhattanPoint intersect(int m, ManhattanCircle a){
		ManhattanPoint newPoint=a.intersect(m,this);
		return newPoint;
	}

	public void draw(Graphics g, int SZ, boolean New) {
		if ((New && getValidNew()) || (!New && getValid())) {
			
			if(New){
				constList.get(0).getNewXYZ(v1);
				constList.get(1).getNewXYZ(v2);
			}
			else{
				constList.get(0).getXYZ(v1);
				constList.get(1).getXYZ(v2);
			}
			if (MathEqns.norm(v1,v2)>.00001) {
				if(type==LINE || type==SEGMENT){
					g.drawLine(SZ+(int)(SZ*v1[0]),SZ+(int)(SZ*v1[1]),
							SZ+(int)(SZ*v2[0]),SZ+(int)(SZ*v2[1]));
					if (getLabelShown()) g.drawString(""+(char)('A'+ID%26)+""+(ID/26),
							SZ+(int)(SZ*(2*v2[0]+v1[0])/3),SZ+(int)(SZ*(2*v2[1]+v1[1])/3));
					if (type==LINE) {//extend the line
						if (Math.abs(v1[0]-v2[0])>.0001) {
						double tmp[]={0,0,0};
						if(v1[0]<v2[0]){
							tmp[0]=v1[0];
							tmp[1]=v1[1];
						}
						else{
							tmp[0]=v2[0];
							tmp[1]=v2[1];						
						}
						double m=(v2[1]-v1[1])/(v2[0]-v1[0]);
						for(double t=-Math.PI/2+.1;t<Math.PI/2-.1;t+=.1){
							x=Math.tan(t)+tmp[0];
							y=m*x+tmp[1]-m*tmp[0];
							g.drawLine(SZ+(int)(SZ*tmp[0]),SZ+(int)(SZ*tmp[1]),
							SZ+(int)(SZ*x),SZ+(int)(SZ*y));
							tmp[0]=x;
							tmp[1]=y;
							if(t<0&&(t+.1>0)){
								if(v1[0]>v2[0]){
									tmp[0]=v1[0];
									tmp[1]=v1[1];
								}
								else{
									tmp[0]=v2[0];
									tmp[1]=v2[1];
								}
							}
						}
						}
						else {
							g.drawLine(SZ+(int)(SZ*v1[0]),0,SZ+(int)(SZ*v1[0]),2*SZ);
						}
					}
				}
			}
		}
	}

	public boolean mouseIsOver(double[] v0, int SZ){
		double[] v2={0,0,0},v={0,0,0},r={0,0,0};
		constList.get(1).getXYZ(v2);
		v[0]=-y;
		v[1]=x;
		MathEqns.normalize(v);

		r[0]=v2[0]-v0[0];
		r[1]=v2[1]-v0[1];
		//Return true if the distance between the line and the point in question is less than
		return Math.abs(MathEqns.dotProduct(v,r))< 0.03;
	}
	public void update() {
		boolean isValidNow=true;
		for (int i=0;i<getSize();i++)
			isValidNow=(isValidNow && get(i).getValidNew());
		setValidNew(isValidNow);
		if (isValidNow) {
			constList.get(0).getNewXYZ(v1);
			constList.get(1).getNewXYZ(v2);			
			if (type==LINE || type==SEGMENT){
				if (MathEqns.norm(v1,v2)>.00001) setNewXYZ(v1,v2);
				else setValidNew(false);
			}
		}
	}
}

class ManhattanCircle extends ManhattanConstruct{
	public ManhattanCircle(int t, ManhattanConstruct a, ManhattanConstruct b) {
		super(t,a,b);
		if (a.getValid() && b.getValid()) setValid(true);
	}
	public ManhattanPoint intersect(int m, ManhattanConstruct a){
		ManhattanPoint newPoint;
		if(a.getType()==0)
			newPoint=intersect(m,(ManhattanCircle)a);
		else
			newPoint=intersect(m,(ManhattanLine)a);
		return newPoint;
	}
	public ManhattanPoint intersect(int m, ManhattanLine a){
		ManhattanPoint newPoint=new ManhattanCIRCintLINE(CIRCintLINE0+m,this,a);
		newPoint.setXYZ(getCLxyz(newPoint,a,m));
		return newPoint;
	}
	public ManhattanPoint intersect(int m, ManhattanCircle a){
		ManhattanPoint newPoint=new ManhattanCIRCintCIRC(CIRCintCIRC00+m,this,a);
		newPoint.setXYZ(getCCxyz(newPoint,a,m));
		return newPoint;
	}

	public void draw(Graphics g, int SZ, boolean New) {
		if ((New && getValidNew()) || (!New && getValid())) {
			double[] center={0,0,0},radial={0,0,0},v1={0,0,0},v2={0,0,0};
			if(New){
				constList.get(0).getNewXYZ(center);
				constList.get(1).getNewXYZ(radial);
			}
			else{
				constList.get(0).getXYZ(center);
				constList.get(1).getXYZ(radial);
			}
			double r=Math.abs(center[0]-radial[0])+Math.abs(center[1]-radial[1]);
			EuclideanSEGMENT c;
			v1[0]=center[0]+r;		v1[1]=center[1];
			v2[0]=center[0];		v2[1]=center[1]+r;
			c=getSegment(v1,v2);	c.draw(g, SZ, New);
			v1[0]=center[0]-r;
			c=getSegment(v1,v2);	c.draw(g, SZ, New);
			v2[1]=center[1]-r;
			c=getSegment(v1,v2);	c.draw(g, SZ, New);
			v1[0]=center[0]+r;
			c=getSegment(v1,v2);	c.draw(g, SZ, New);			
			if (getLabelShown())
				g.drawString(""+(char)('A'+ID%26)+""+(ID/26),SZ+(int)(SZ*(center[0]+r/2)),SZ+(int)(SZ*(center[1]+r/2)));	  
		}
	}
	public EuclideanSEGMENT getSegment(double[] v1, double[] v2){	// we use Euclidean segments
		EuclideanPoint a=new EuclideanPoint(POINT,v1);				// to draw Manhattan circles
		EuclideanPoint b=new EuclideanPoint(POINT,v2);
		LinkedList<GeoConstruct> temp=new LinkedList<GeoConstruct>();
		temp.add(a);	temp.add(b);
		EuclideanSEGMENT c=new EuclideanSEGMENT(SEGMENT,temp);
		c.update();
		return c;
	}
	public boolean mouseIsOver(double[] mouse, int SZ){
		double[] axis={0,0,0}, point={0,0,0};
		double radius,dFromAxis;
		constList.get(0).getXYZ(axis);
		constList.get(1).getXYZ(point);
		radius=Math.abs(axis[0]-point[0])+Math.abs(axis[1]-point[1]);
		dFromAxis=Math.abs(axis[0]-mouse[0])+Math.abs(axis[1]-mouse[1]);
		return Math.abs(radius-dFromAxis)<0.03;
	}

	public void update() {
		setValidNew(constList.get(0).getValidNew() && constList.get(1).getValidNew());
	}
	public double[] getCLxyz(ManhattanPoint inter, ManhattanConstruct b, int i) {
		double[] u={0,0,0},v={0,0,0},w={0,0,0},z={0,0,0},x={0,0,0};
		get(0).getXYZ(u); 
		get(1).getXYZ(v);
		b.getXYZ(w);
		b.get(1).getXYZ(z);
		inter.setValid(CircleEqns.calculateManCL(u,v,w,z,x,(i==0)));
		return x;
	}

	public double[] getNewCLxyz(ManhattanPoint inter,ManhattanConstruct b, int i) {
		double[] u={0,0,0},v={0,0,0},w={0,0,0},z={0,0,0},x={0,0,0};
		get(0).getNewXYZ(u);
		get(1).getNewXYZ(v);
		b.getNewXYZ(w);
		b.get(1).getNewXYZ(z);
		inter.setValidNew(CircleEqns.calculateManCL(u,v,w,z,x,(i==0)));
		return x;
	}
	public double[] getCCxyz(ManhattanPoint inter,ManhattanConstruct b, int i) {
		double[] t={0,0,0},u={0,0,0},v={0,0,0},w={0,0,0},x={0,0,0};
		get(0).getXYZ(t);
		get(1).getXYZ(u);
		b.get(0).getXYZ(v);
		b.get(1).getXYZ(w);
		if (t[0]==v[0]) v[0]+=.00000001;
		inter.setValid(CircleEqns.calculateManCC(t,u,v,w,x,(i==0)));
		return x;
	}
	public double[] getNewCCxyz(ManhattanPoint inter,ManhattanConstruct b, int i) {
		double[] t={0,0,0},u={0,0,0},v={0,0,0},w={0,0,0},x={0,0,0};
		get(0).getNewXYZ(t);
		get(1).getNewXYZ(u);
		b.get(0).getNewXYZ(v);
		b.get(1).getNewXYZ(w);
		if (t[0]==v[0]) v[0]+=.00000001;
		inter.setValidNew(CircleEqns.calculateManCC(t,u,v,w,x,(i==0)));
		return x;
	}

}

class ManhattanPTonLINE extends ManhattanPoint {
	public ManhattanPTonLINE(int t, double[] vector) {super(t, vector);}
	public ManhattanPTonLINE(int t, double[] v1, double[] v2) {super(t, v1, v2);}
	public ManhattanPTonLINE(int t, double[] v, ManhattanConstruct a) {super(t, v, a);}
	public ManhattanPTonLINE(int t, ManhattanConstruct a,ManhattanConstruct b) {super(t, a, b);}
	public ManhattanPTonLINE(int t, LinkedList<GeoConstruct> clickedList,double[] v) {super(t, clickedList, v);}
	public void update() {
		super.update();
		updatePTonLINE();
	}
}

class ManhattanPTonCIRC extends ManhattanPoint {
	public ManhattanPTonCIRC(int t, double[] vector) {super(t, vector);}
	public ManhattanPTonCIRC(int t, double[] v1, double[] v2) {super(t, v1, v2);}
	public ManhattanPTonCIRC(int t, double[] v, ManhattanConstruct a) {super(t, v, a);}
	public ManhattanPTonCIRC(int t, ManhattanConstruct a,ManhattanConstruct b) {super(t, a, b);}
	public ManhattanPTonCIRC(int t, LinkedList<GeoConstruct> clickedList,double[] v) {super(t, clickedList, v);}
	public void update() {
		super.update();
		updatePTonCIRC();
	}
}

class ManhattanLINEintLINE extends ManhattanPoint {
	public ManhattanLINEintLINE(int t, double[] vector) {super(t, vector);}
	public ManhattanLINEintLINE(int t, double[] v1, double[] v2) {super(t, v1, v2);}
	public ManhattanLINEintLINE(int t, double[] v, ManhattanConstruct a) {super(t, v, a);}
	public ManhattanLINEintLINE(int t, ManhattanConstruct a,ManhattanConstruct b) {super(t, a, b);}
	public ManhattanLINEintLINE(int t, LinkedList<GeoConstruct> clickedList,double[] v) {super(t, clickedList, v);}
	public void update() {
		double[] v1={0,0,0},v2={0,0,0},nm={0,0,0};
		get(0).getNewXYZ(v1);
		get(1).getNewXYZ(v2);
		nm[2]=v2[0]*v1[1]-v2[1]*v1[0];
		double[] point1={0,0,0},point2={0,0,0};
		get(0).get(1).getNewXYZ(point1);
		get(1).get(1).getNewXYZ(point2);

		double s=((point2[1]-point1[1])*v1[0] - (point2[0]-point1[0])*v1[1])/(v2[0]*v1[1]-v2[1]*v1[0]);
		if (MathEqns.dotProduct(nm,nm)>0) {
			nm[0]=v2[0]*s+point2[0];
			nm[1]=v2[1]*s+point2[1];
			nm[2]=0;
			setValidNew(true);
			setNewXYZ(nm);
			for (int i=0;i<2;i++) if (constList.get(i).getType()==SEGMENT) {
				constList.get(i).get(0).getNewXYZ(v1);
				constList.get(i).get(1).getNewXYZ(v2);
				if (Math.abs(Math.abs(v1[0]-v2[0])+Math.abs(v1[1]-v2[1])-
							 Math.abs(v1[0]-nm[0])-Math.abs(v1[1]-nm[1])-
							 Math.abs(nm[0]-v2[0])-Math.abs(nm[1]-v2[1]))>.001)
					setValidNew(false);
			}
		}
		else setValid(false);
	}
}

class ManhattanCIRCintLINE extends ManhattanPoint {
	public ManhattanCIRCintLINE(int t, double[] vector) {super(t, vector);}
	public ManhattanCIRCintLINE(int t, double[] v1, double[] v2) {super(t, v1, v2);}
	public ManhattanCIRCintLINE(int t, double[] v, ManhattanConstruct a) {super(t, v, a);}
	public ManhattanCIRCintLINE(int t, ManhattanConstruct a,ManhattanConstruct b) {super(t, a, b);}
	public ManhattanCIRCintLINE(int t, LinkedList<GeoConstruct> clickedList,double[] v) {super(t, clickedList, v);}
	public void update() {
		setNewXYZ(((ManhattanCircle)constList.get(0)).getNewCLxyz(this,(ManhattanConstruct)constList.get(1),type-CIRCintLINE0));
		double[] nm={newX,newY,newZ};
		for (int i=0;i<2;i++) if (constList.get(i).getType()==SEGMENT) {
			constList.get(i).get(0).getNewXYZ(v1);
			constList.get(i).get(1).getNewXYZ(v2);
			if (Math.abs(Math.abs(v1[0]-v2[0])+Math.abs(v1[1]-v2[1])-
					 Math.abs(v1[0]-nm[0])-Math.abs(v1[1]-nm[1])-
					 Math.abs(nm[0]-v2[0])-Math.abs(nm[1]-v2[1]))>.001)
			setValidNew(false);
		}
	}
}

class ManhattanCIRCintCIRC extends ManhattanPoint {
	public ManhattanCIRCintCIRC(int t, double[] vector) {super(t, vector);}
	public ManhattanCIRCintCIRC(int t, double[] v1, double[] v2) {super(t, v1, v2);}
	public ManhattanCIRCintCIRC(int t, double[] v, ManhattanConstruct a) {super(t, v, a);}
	public ManhattanCIRCintCIRC(int t, ManhattanConstruct a,ManhattanConstruct b) {super(t, a, b);}
	public ManhattanCIRCintCIRC(int t, LinkedList<GeoConstruct> clickedList,double[] v) {super(t, clickedList, v);}
	public void update() {
		setNewXYZ(((ManhattanCircle)constList.get(0)).getNewCCxyz(this,(ManhattanConstruct)constList.get(1),type-CIRCintCIRC00));
	}
}

class ManhattanMIDPT extends ManhattanPoint {
	public ManhattanMIDPT(int t, double[] vector) {super(t, vector);}
	public ManhattanMIDPT(int t, double[] v1, double[] v2) {super(t, v1, v2);}
	public ManhattanMIDPT(int t, double[] v, ManhattanConstruct a) {super(t, v, a);}
	public ManhattanMIDPT(int t, ManhattanConstruct a,ManhattanConstruct b) {super(t, a, b);}
	public ManhattanMIDPT(int t, LinkedList<GeoConstruct> clickedList,double[] v) {super(t, clickedList, v);}
	public void update() {
		super.update();
		constList.get(0).getNewXYZ(v1);
		constList.get(1).getNewXYZ(v2);
		v1[0]=(v1[0]+v2[0])/2;
		v1[1]=(v1[1]+v2[1])/2;
		setNewXYZ(v1);
	}
}

class ManhattanFIXedPT extends ManhattanPoint {
	public ManhattanFIXedPT(int t, double[] vector) {super(t, vector);}
	public ManhattanFIXedPT(int t, double[] v1, double[] v2) {super(t, v1, v2);}
	public ManhattanFIXedPT(int t, double[] v, ManhattanConstruct a) {super(t, v, a);}
	public ManhattanFIXedPT(int t, ManhattanConstruct a,ManhattanConstruct b) {super(t, a, b);}
	public ManhattanFIXedPT(int t, LinkedList<GeoConstruct> clickedList,double[] v) {super(t, clickedList, v);}
}

class ManhattanMeasure extends ManhattanPoint {
    protected double[] a={0,0,0},b={0,0,0};
	public ManhattanMeasure(int t, double[] vector) {super(t, vector);}
	public ManhattanMeasure(int t, double[] v1, double[] v2) {super(t, v1, v2);}
	public ManhattanMeasure(int t, double[] v, ManhattanConstruct a) {super(t, v, a);}
	public ManhattanMeasure(int t, ManhattanConstruct a,ManhattanConstruct b) {super(t, a, b);}
	public ManhattanMeasure(int t, LinkedList<GeoConstruct> clickedList,double[] v) {super(t, clickedList, v);}
	public void draw(Graphics g, int SZ, boolean New) {
		super.draw(g, SZ, New);
		if (New && (getType()!=ANGLE && getType()!=RATIO)) {
			get(0).get(0).getNewXYZ(a);
			get(0).get(1).getNewXYZ(b);
		}
		else if (getType()!=ANGLE && getType()!=RATIO) {
			get(0).get(0).getXYZ(a);
			get(0).get(1).getXYZ(b);
		}
		g.fillRect(SZ+(int)(SZ*v1[0])-sz/2+1,SZ+(int)(SZ*v1[1])-sz/2+1,sz-2,sz-2);
		g.drawLine(SZ+(int)(SZ*v1[0]),SZ+(int)(SZ*v1[1]),SZ+(int)(SZ*v1[0])+10,SZ+(int)(SZ*v1[1])-5);		
	}

}
class ManhattanRATIO extends ManhattanMeasure {
	public ManhattanRATIO(int t, double[] vector) {super(t, vector);}
	public ManhattanRATIO(int t, double[] v1, double[] v2) {super(t, v1, v2);}
	public ManhattanRATIO(int t, double[] v, ManhattanConstruct a) {super(t, v, a);}
	public ManhattanRATIO(int t, ManhattanConstruct a,ManhattanConstruct b) {super(t, a, b);}
	public ManhattanRATIO(int t, LinkedList<GeoConstruct> clickedList,double[] v) {
		super(t, clickedList, v);
	}
	public void draw(Graphics g, int SZ, boolean New) {
		if ((New && getValidNew()) || (!New && getValid())) {
		super.draw(g, SZ, New);
		String[] ratioText={"",""};
		double[] ratioVar={0,0};
		for (int i=0;i<2;i++) {
			if (New) {
				get(i).get(0).get(0).getNewXYZ(a);
				get(i).get(0).get(1).getNewXYZ(b);
			}
			else {
				get(i).get(0).get(0).getXYZ(a);
				get(i).get(0).get(1).getXYZ(b);
			}
			switch(get(i).getType()) {
			case DISTANCE:
				ratioText[i]="d("+(char)('A'+get(i).get(0).get(0).getID()%26)+""+(get(i).get(0).get(0).getID()/26)+","
				+(char)('A'+get(i).get(0).get(1).getID()%26)+""+(get(i).get(0).get(1).getID()/26)+")";
				ratioVar[i]=Math.abs(a[0]-b[0])+Math.abs(a[1]-b[1]);
				break;
			case ANGLE:
				double[] c={0,0,0};
				if (New) get(i).get(0).get(2).getNewXYZ(c);
				else get(i).get(0).get(2).getXYZ(c);
				ratioText[i]="m\u2220("+(char)('A'+get(i).get(0).get(0).getID()%26)+""+(get(i).get(0).get(0).getID()/26)+","
				+(char)('A'+get(i).get(0).get(1).getID()%26)+""+(get(i).get(0).get(1).getID()/26)+","
				+(char)('A'+get(i).get(0).get(2).getID()%26)+""+(get(i).get(0).get(2).getID()/26)+")";
				ratioVar[i]=MathEqns.eucAngle(a,b,c);
				break;
			case AREA:
				ratioText[i]="a("+(char)('A'+get(i).get(0).getID()%26)+""+(get(i).get(0).getID()/26)+")";
				ratioVar[i]=4*(Math.abs(a[0]-b[0])+Math.abs(a[1]-b[1]))*(Math.abs(a[0]-b[0])+Math.abs(a[1]-b[1]));
				break;
			case CIRCUMF:
				ratioText[i]="c("+(char)('A'+get(i).get(0).getID()%26)+""+(get(i).get(0).getID()/26)+")";
				ratioVar[i]=8*Math.abs(a[0]-b[0])+8*Math.abs(a[1]-b[1]);
				break;
			}
		}
		String calcText="-";
		if (ratioVar[1]!=0) calcText=""+MathEqns.chop(ratioVar[0]/ratioVar[1]);
		g.drawString(ratioText[0]+":"+ratioText[1]+"\u2248"+calcText,SZ+(int)(SZ*v1[0])+13,SZ+(int)(SZ*v1[1]));
		}
	}
	public void update() {
		super.update();
	}
}
class ManhattanDISTANCE extends ManhattanMeasure {
	public ManhattanDISTANCE(int t, double[] vector) {super(t, vector);}
	public ManhattanDISTANCE(int t, double[] v1, double[] v2) {super(t, v1, v2);}
	public ManhattanDISTANCE(int t, double[] v, ManhattanConstruct a) {super(t, v, a);}
	public ManhattanDISTANCE(int t, ManhattanConstruct a,ManhattanConstruct b) {super(t, a, b);}
	public ManhattanDISTANCE(int t, LinkedList<GeoConstruct> clickedList,double[] v) {
		super(t, clickedList, v);
	}
	public void draw(Graphics g, int SZ, boolean New) {
		if ((New && getValidNew()) || (!New && getValid())) {
		super.draw(g, SZ, New);
		g.drawString("d("+(char)('A'+get(0).get(0).getID()%26)+""+(get(0).get(0).getID()/26)+","
				+(char)('A'+get(0).get(1).getID()%26)+""+(get(0).get(1).getID()/26)+")\u2248"
				+MathEqns.chop(Math.abs(a[0]-b[0])+Math.abs(a[1]-b[1])),
				SZ+(int)(SZ*v1[0])+13,SZ+(int)(SZ*v1[1]));
		}
	}
	public void update() {
		super.update();
		updatePTonLINE();
	}
}

class ManhattanANGLE extends ManhattanMeasure {
	public ManhattanANGLE(int t, double[] vector) {super(t, vector);}
	public ManhattanANGLE(int t, double[] v1, double[] v2) {super(t, v1, v2);}
	public ManhattanANGLE(int t, double[] v, ManhattanConstruct a) {super(t, v, a);}
	public ManhattanANGLE(int t, ManhattanConstruct a,ManhattanConstruct b) {super(t, a, b);}
	public ManhattanANGLE(int t, LinkedList<GeoConstruct> clickedList,double[] v) {super(t, clickedList, v);}
	public void draw(Graphics g, int SZ, boolean New) {
		if ((New && getValidNew()) || (!New && getValid())) {
		super.draw(g, SZ, New);
		double[] c={0,0,0};
		if (New) {
			get(0).get(0).getNewXYZ(a);get(0).get(1).getNewXYZ(b);get(0).get(2).getNewXYZ(c);
		}
		else {
			get(0).get(0).getXYZ(a);get(0).get(1).getXYZ(b);get(0).get(2).getXYZ(c);
		}
		g.drawString("m\u2220("+(char)('A'+get(0).get(0).getID()%26)+""+(get(0).get(0).getID()/26)+","
				+(char)('A'+get(0).get(1).getID()%26)+""+(get(0).get(1).getID()/26)+","
				+(char)('A'+get(0).get(2).getID()%26)+""+(get(0).get(2).getID()/26)+")\u2248"
				+MathEqns.chop(MathEqns.eucAngle(a,b,c))+"\u00b0",
				SZ+(int)(SZ*v1[0])+13,SZ+(int)(SZ*v1[1]));
		}
	}
	public void update() {
		super.update();
		updatePTonLINE();
	}
}

class ManhattanCIRCUMF extends ManhattanMeasure {
	public ManhattanCIRCUMF(int t, double[] vector) {super(t, vector);}
	public ManhattanCIRCUMF(int t, double[] v1, double[] v2) {super(t, v1, v2);}
	public ManhattanCIRCUMF(int t, double[] v, ManhattanConstruct a) {super(t, v, a);}
	public ManhattanCIRCUMF(int t, ManhattanConstruct a,ManhattanConstruct b) {super(t, a, b);}
	public ManhattanCIRCUMF(int t, LinkedList<GeoConstruct> clickedList,double[] v) {super(t, clickedList, v);}
	public void draw(Graphics g, int SZ, boolean New) {
		if ((New && getValidNew()) || (!New && getValid())) {
		super.draw(g, SZ, New);
		g.drawString("c("+(char)('A'+constList.get(0).getID()%26)+""+(constList.get(0).getID()/26)+")\u2248"
				+MathEqns.chop(8*Math.abs(a[0]-b[0])+8*Math.abs(a[1]-b[1])),
				SZ+(int)(SZ*v1[0])+13,SZ+(int)(SZ*v1[1]));
		}
	}
	public void update() {
		super.update();
		updatePTonCIRC();
	}
}

class ManhattanAREA extends ManhattanMeasure {
	public ManhattanAREA(int t, double[] vector) {super(t, vector);}
	public ManhattanAREA(int t, double[] v1, double[] v2) {super(t, v1, v2);}
	public ManhattanAREA(int t, double[] v, ManhattanConstruct a) {super(t, v, a);}
	public ManhattanAREA(int t, ManhattanConstruct a,ManhattanConstruct b) {super(t, a, b);}
	public ManhattanAREA(int t, LinkedList<GeoConstruct> clickedList,double[] v) {super(t, clickedList, v);}
	public void draw(Graphics g, int SZ, boolean New) {
		if ((New && getValidNew()) || (!New && getValid())) {
		super.draw(g, SZ, New);
		g.drawString("a("+(char)('A'+constList.get(0).getID()%26)+""+(constList.get(0).getID()/26)+")\u2248"
				+MathEqns.chop(4*(Math.abs(a[0]-b[0])+Math.abs(a[1]-b[1]))*(Math.abs(a[0]-b[0])+Math.abs(a[1]-b[1]))),
				SZ+(int)(SZ*v1[0])+13,SZ+(int)(SZ*v1[1]));
		}
	}
	public void update() {
		super.update();
		updatePTonCIRC();
	}
}

class ManhattanPERP extends ManhattanLine {
	public ManhattanPERP(int t, LinkedList<GeoConstruct> clickedList) {
		super(t, clickedList);
		x=-clickedList.get(0).y;y=clickedList.get(0).x;
	}
	public void draw(Graphics g, int SZ, boolean New) {
		super.draw(g, SZ, New);
		if ((New & getValidNew()) || (!New && getValid())) switch(GeoPlayground.model){
		case 0:
			if (New) getNewXYZ(v1);
			else getXYZ(v1);
			a[0]=v1[0];a[1]=v1[1];
			MathEqns.normalize(a);
			g.drawLine(SZ+(int)(SZ*v2[0]-5*SZ*a[0]),SZ+(int)(SZ*v2[1]-5*SZ*a[1]),SZ+(int)(SZ*v2[0]+5*SZ*a[0]),SZ+(int)(SZ*v2[1]+5*SZ*a[1]));
			if (getLabelShown()) g.drawString(""+(char)('A'+ID%26)+""+(ID/26),
					SZ+(int)(SZ*(v2[0]+a[0]/2.)),SZ+(int)(SZ*(v2[1]+a[1]/2.)));
			break;
		case 1:
		case 2: 
		case 3: 
		}	
	}
	public void update() {
		super.update();
		if(getValidNew()){
			v2[0]=-v1[1];
			v2[1]=v1[0];
			setNewXYZ(v2);
		}
	}
}

class ManhattanSEGMENT extends ManhattanLine {
	public ManhattanSEGMENT(int t, LinkedList<GeoConstruct> clickedList) {super(t, clickedList);}
	public void draw(Graphics g, int SZ, boolean New) {
		super.draw(g, SZ, New);
		if (MathEqns.norm(v1,v2)>.00001) switch(GeoPlayground.model){
		case 0:
			break;
		case 1:
			for (int i=0;i<48;i++) {
				u[0]=v2[0]+i/48.*a[0];
				u[1]=v2[1]+i/48.*a[1];
				u[2]=Math.sqrt(1+u[0]*u[0]+u[1]*u[1]);
				u[0]/=u[2];		u[1]/=u[2];
				v[0]=v2[0]+(i+1)/48.*a[0];
				v[1]=v2[1]+(i+1)/48.*a[1];
				v[2]=Math.sqrt(1+v[0]*v[0]+v[1]*v[1]);
				v[0]/=v[2];		v[1]/=v[2];
				g.drawLine(SZ+(int)(SZ*u[0]),SZ+(int)(SZ*u[1]),SZ+(int)(SZ*v[0]),SZ+(int)(SZ*v[1]));
				if (getLabelShown() && i==16)
					g.drawString(""+(char)('A'+ID%26)+""+(ID/26),SZ+(int)(SZ*u[0]),SZ+(int)(SZ*u[1]));
			}
			break;
		case 2: 
		case 3: 
			for (int i=0;i<128;i++) {
				u[0]=v2[0]+i/128.*a[0];
				u[1]=v2[1]+i/128.*a[1];
				u[2]=u[0]*u[0]+u[1]*u[1];
				u[0]/=u[2];		u[1]/=u[2];
				v[0]=v2[0]+(i+1)/128.*a[0];
				v[1]=v2[1]+(i+1)/128.*a[1];
				v[2]=v[0]*v[0]+v[1]*v[1];
				v[0]/=v[2];		v[1]/=v[2];
				g.drawLine(SZ+(int)(SZ*u[0]),SZ+(int)(SZ*u[1]),SZ+(int)(SZ*v[0]),SZ+(int)(SZ*v[1]));
				if (getLabelShown() && i==21)
					g.drawString(""+(char)('A'+ID%26)+""+(ID/26),SZ+(int)(SZ*u[0]),SZ+(int)(SZ*u[1]));
			}	
			break;
		}
	}

}

class ManhattanBISECTOR extends ManhattanLine {

	public ManhattanBISECTOR(int t, LinkedList<GeoConstruct> clickedList) {
		super(t, clickedList);
		double[] v1={0,0,0}, v2={0,0,0}, aa={0,0,0},bb={0,0,0},cc={0,0,0};
		clickedList.get(0).getXYZ(aa);
		EuclideanPoint a=new EuclideanPoint(POINT,aa);
		clickedList.get(1).getXYZ(bb);
		EuclideanPoint b=new EuclideanPoint(POINT,bb);
		clickedList.get(2).getXYZ(cc);
		EuclideanPoint c=new EuclideanPoint(POINT,cc);
		LinkedList<GeoConstruct>tempList=new LinkedList<GeoConstruct>();
		tempList.add(b);
		tempList.add(c);
		EuclideanLine d=new EuclideanLine(LINE,tempList);
		EuclideanCircle e=new EuclideanCircle(CIRCLE,b,a);
		EuclideanPoint f1,f2;
		f1=((EuclideanLine)d).intersect(0,(EuclideanCircle)e);
		f2=((EuclideanLine)d).intersect(1,(EuclideanCircle)e);
		tempList.clear();	tempList.add(a);	tempList.add(f1);
		EuclideanPoint g1=new EuclideanMIDPT(MIDPT,tempList,v1);
		tempList.clear();	tempList.add(a);	tempList.add(f2);
		EuclideanPoint g2=new EuclideanMIDPT(MIDPT,tempList,v2);
		tempList.clear();	tempList.add(a);	tempList.add(c);
		if (MathEqns.norm(v1,bb)>MathEqns.norm(v2,bb)) {
			g1=g2;
		}
		tempList.clear();	tempList.add(b);	tempList.add(g1);
		EuclideanLine h=new EuclideanLine(LINE,tempList);
		x=h.getNewX();y=h.getNewY();z=0;
		newX=x;newY=y;newZ=z;
	}

	public void draw(Graphics g, int SZ, boolean New) {
		super.draw(g, SZ, New);
		if (MathEqns.norm(v1,v2)>.00001) switch(GeoPlayground.model){
		case 0:
			if (New) getNewXYZ(v1);
			else getXYZ(v1);
			a[0]=v1[0];a[1]=v1[1];
			MathEqns.normalize(a);
			g.drawLine(SZ+(int)(SZ*v2[0]-5*SZ*a[0]),SZ+(int)(SZ*v2[1]-5*SZ*a[1]),SZ+(int)(SZ*v2[0]+5*SZ*a[0]),SZ+(int)(SZ*v2[1]+5*SZ*a[1]));
			if (getLabelShown()) g.drawString(""+(char)('A'+ID%26)+""+(ID/26),
					SZ+(int)(SZ*(v2[0]+a[0]/2.)),SZ+(int)(SZ*(v2[1]+a[1]/2.)));
		case 1:
		case 2: 
		case 3: 
		}
	}
	public void update() {
		super.update();
		if(getValidNew()){
			double[] aa={0,0,0},bb={0,0,0},cc={0,0,0};
			constList.get(0).getNewXYZ(aa);
			EuclideanPoint a=new EuclideanPoint(POINT,aa);
			constList.get(1).getNewXYZ(bb);
			EuclideanPoint b=new EuclideanPoint(POINT,bb);
			constList.get(2).getNewXYZ(cc);
			EuclideanPoint c=new EuclideanPoint(POINT,cc);
			LinkedList<GeoConstruct>tempList=new LinkedList<GeoConstruct>();
			tempList.add(b);	tempList.add(c);
			EuclideanLine d=new EuclideanLine(LINE,tempList);
			d.update();	d.getNewXYZ(v1);
			EuclideanCircle e=new EuclideanCircle(CIRCLE,b,a);
			EuclideanPoint f1,f2;
			f1=((EuclideanLine)d).intersect(0,(EuclideanCircle)e);
			f1.update();	f1.getNewXYZ(v1);	f1.setXYZ(v1);
			f2=((EuclideanLine)d).intersect(1,(EuclideanCircle)e);
			f2.update();	f2.getNewXYZ(v2);	f2.setXYZ(v2);
			tempList.clear();	tempList.add(a);	tempList.add(f1);
			EuclideanPoint g1=new EuclideanMIDPT(MIDPT,tempList,v1);
			g1.update();	g1.getNewXYZ(v1);	g1.setXYZ(v1);
			tempList.clear();	tempList.add(a);	tempList.add(f2);
			EuclideanPoint g2=new EuclideanMIDPT(MIDPT,tempList,v2);
			g2.update();	g2.getNewXYZ(v2);	g2.setXYZ(v2);
			tempList.clear();	tempList.add(a);	tempList.add(c);
			EuclideanPoint g3=new EuclideanMIDPT(MIDPT,tempList,bb);
			g3.update();	g3.getNewXYZ(bb);	g3.setXYZ(bb);
			if (MathEqns.norm(v1,bb)>MathEqns.norm(v2,bb)) {
				g1=g2;
			}
			tempList.clear();	tempList.add(b);	tempList.add(g1);
			EuclideanLine h=new EuclideanLine(LINE,tempList);
			h.update();	h.getNewXYZ(v1);
			if (MathEqns.norm(v1)<=.00001) {
				tempList.clear();	tempList.add(a);	tempList.add(b);
				d=new EuclideanLine(LINE,tempList);
				d.update();			d.getNewXYZ(v1);	d.setXYZ(v1);
				tempList.clear();	tempList.add(d);	tempList.add(b);
				h=new EuclideanPERP(PERP,tempList);
				h.update();	h.getNewXYZ(v1);
			}
			if (MathEqns.norm(v1)>.00001) setNewXYZ(v1);
			else setValidNew(false);
		}
	}
}
